package com.zhiqian.rpc;

import com.zhiqian.serializer.CommonDecoder;
import com.zhiqian.serializer.CommonEncoder;
import com.zhiqian.serializer.impl.HessianSerializer;
import com.zhiqian.service.AbstractRpcServer;
import com.zhiqian.service.ServiceProvider;
import com.zhiqian.service.ServiceRegistry;
import com.zhiqian.service.impl.DefaultServiceProvider;
import com.zhiqian.service.impl.ZookeeperServiceRegistry;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;

@Slf4j
public class NettyServer extends AbstractRpcServer {
    private static ServiceProvider serviceProvider;
    private ServiceRegistry serviceRegistry;
    private final int port;

    static{
        serviceProvider=new DefaultServiceProvider();
    }
    public NettyServer(String hostName,int port){
        serviceRegistry=new ZookeeperServiceRegistry(hostName);
        this.port=port;
        scanServices();
    }

    @Override
    public <T> void publishService(Object object) {
        Class<?> clazz = object.getClass();
        Class<?>[] interfaces = clazz.getInterfaces();
        String className = interfaces[0].getName();
        String hostAddress=null;
        try {
            hostAddress = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        serviceProvider.register(object);
        serviceRegistry.registry(className,new InetSocketAddress(hostAddress,port));
    }

    @Override
    public void start() {
        EventLoopGroup bossGroup = new NioEventLoopGroup();//用于处理服务器端接收客户端连接的线程组
        EventLoopGroup workerGroup = new NioEventLoopGroup();//用于进行网络通信的线程组（网络读写）
        try{
            ServerBootstrap serverBootstrap = new ServerBootstrap();//辅助工具类，用于服务器通信的一系列配置
            serverBootstrap.group(bossGroup,workerGroup)//绑定两个线程组
                    .channel(NioServerSocketChannel.class)//指定nio的模式
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .option(ChannelOption.SO_BACKLOG,256)//设置TCP缓冲区
                    .option(ChannelOption.SO_KEEPALIVE,true)//保持连接
                    .childOption(ChannelOption.TCP_NODELAY,true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline= socketChannel.pipeline();
                            pipeline.addLast(new CommonEncoder(new HessianSerializer()));//编码器
                            pipeline.addLast(new CommonDecoder());//解码器
                            pipeline.addLast(new NettyServerHandler());//数据处理器
                        }
                    });
            ChannelFuture future=serverBootstrap.bind(port).sync();//进行绑定
            future.channel().closeFuture().sync();//等待关闭
        }catch (InterruptedException e){
            log.error("启动服务器时有错误发生：{}",e);
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
